﻿/***************************************************************
*       
* add by OceanHo 2015/8/26 13:49:22
*
****************************************************************/

using Enyim.Caching;
using Enyim.Caching.Memcached;
using oceanho.webapi.factory.httpEntity;
using oceanho.webapi.factory.httpUtility;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Web;

namespace oceanho.webapi.factory.httpCore.ReqKernal
{
    /// <summary>
    /// 定义：客户端请求 ReqCache 数据库（使用memcached访问客户端的服务器信息，是 DefaultReqCacheDb 实现 IReqCacheDb的核心类 ）
    /// </summary>
    internal sealed class DefaultReqCacheDbKernal
    {
        /// <summary>
        /// MemcachedClient
        /// </summary>
        private static MemcachedClient client = new MemcachedClient("reqcacheDb/memcached");

        #region -- ReqCacheDb --

        /// <summary>
        /// 获取Memcached中的缓存的ReqCache对象,有缓存返回缓存的ReqCache,否则返回null
        /// </summary>
        /// <param name="request">HttpRequest对象</param>
        internal static ReqCache Get(HttpRequest request)
        {
            return client.Get<ReqCache>(RequestUtility.GetReqID(request));
        }
        /// <summary>
        /// 获取Memcached中的缓存的ReqCache对象,有缓存返回缓存的ReqCache,否则new ReqCache返回
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <param name="isCached">对象是否是缓存的（输出参数）</param>
        /// <returns></returns>
        internal static ReqCache Get(string key, out bool isCached)
        {
            ReqCache reqCache = client.Get<ReqCache>(key);
            isCached = reqCache != null;
            if (reqCache == null)
            {
                reqCache = new ReqCache(key)
                {
                    Req_Warn_Lv = 1,
                    Req_Wait_Count = 1,
                    Req_Seconds_Count = 1,
                    Req_Pre_Date = DateTime.Now,

                    // 默认10分钟后才可以重置此请求的IsBadIP标识
                    Req_Allow_Clear_IsBadIP_Date = DateTime.Now.AddMinutes(AppUtility.Cfg.Allow_ClearIsBadIP_Wait_Minutes),
                };
            }
            return reqCache;
        }

        /// <summary>
        /// 获取Memcached中的缓存的ReqCache对象,有缓存返回缓存的ReqCache,否则返回null
        /// </summary>
        /// <param name="key">缓存键</param>
        /// <returns></returns>
        internal static ReqCache GetReqCache(string key)
        {
            return client.Get<ReqCache>(key);
        }

        /// <summary>
        /// 缓存ReqCache到Memcached中
        /// </summary>
        /// <param name="request">HttpRequest对象</param>
        /// <param name="key">缓存键</param>
        /// <param name="reqCache">缓存值</param>
        /// <param name="isCached">是否是已经缓存过的值</param>
        /// <param name="isForever">是否永远缓存</param>
        internal static bool Set(HttpRequest request, string key, ReqCache reqCache, bool isCached, bool isForever)
        {
            StoreMode mode = StoreMode.Replace;
            if (!isCached)
            {
                mode = StoreMode.Add;
                reqCache.IP = RequestUtility.GetIP(request);
            }
            reqCache.Req_Pre_Date = DateTime.Now;
            return client.Store(mode, key, reqCache, DefaultReqCacheDbKernal.GetCacheTS(isForever));
        }

        /// <summary>
        /// 移除ReqCache的IsBadIP标识
        /// </summary>
        /// <param name="reqCache">ReqCache对象</param>
        /// <param name="isForce">是否不检验reqCache.IsBadIP标识进行强制重置IdBadIP</param>
        internal static void RemoveBadIP(ref ReqCache reqCache, bool isForce = false)
        {
            if (isForce)
            {
                reqCache.Req_Wait_Count = 0;
                reqCache.Req_Seconds_Count = 0;
                reqCache.IsPassBadIPValid = false;
                reqCache.Req_Allow_Clear_IsBadIP_Date = DateTime.Now.AddMinutes(AppUtility.Cfg.Allow_ClearIsBadIP_Wait_Minutes);
            }
            else
            {
                if (reqCache.IsBadIP)
                {
                    reqCache.Req_Wait_Count = 0;
                    reqCache.Req_Seconds_Count = 0;
                    reqCache.IsPassBadIPValid = false;
                    reqCache.Req_Allow_Clear_IsBadIP_Date = DateTime.Now.AddMinutes(AppUtility.Cfg.Allow_ClearIsBadIP_Wait_Minutes);
                }
            }
        }

        /// <summary>
        /// 将ReqCache的Req_Allow_Clear_IsBadIP_Date添加到最大时间（此ReqCache对象将永远被禁止访问，直到解除为止）
        /// </summary>
        /// <param name="reqCache">ReqCache对象</param>
        internal static void SetBadIPForever(ref ReqCache reqCache)
        {
            reqCache.IsPassBadIPValid = false;
            reqCache.Req_Allow_Clear_IsBadIP_Date = DateTime.MaxValue;
        }

        /// <summary>
        /// 将ReqCache的IsPassBadIPValid设置为True，标识此ReqCache永远在黑名单IP外
        /// </summary>
        /// <param name="reqCache">ReqCache对象</param>
        internal static void SetIsValidIPForever(ref ReqCache reqCache)
        {
            reqCache.IsPassBadIPValid = true;
        }

        /// <summary>
        /// 添加/减少请求挂起的次数（addNum大于0，表示添加，否则减少）
        /// </summary>
        /// <param name="reqCache">需要调整的ReqCache对象</param>
        /// <param name="addNum">添加/减少的次数</param>
        internal static void AddReq_Wait_Count(ref ReqCache reqCache, int addNum)
        {
            reqCache.Req_Wait_Count += addNum;
            reqCache.Req_Pre_Date = DateTime.Now;
        }

        /// <summary>
        /// 添加/减少单位时间内的请求次数（addNum大于0，表示添加，否则减少）
        /// </summary>
        /// <param name="reqCache">需要调整的ReqCache对象</param>
        /// <param name="addNum">添加/减少的次数</param>
        internal static void AddReq_Seconds_Count(ref ReqCache reqCache, int addNum)
        {
            reqCache.Req_Seconds_Count += addNum;
        }

        /// <summary>
        /// 校验IP地址是否不属于黑名单IP
        /// </summary>
        /// <param name="reqCache">需要校验的ReqCache对象</param>
        /// <returns></returns>
        internal static bool IsValidIP(ReqCache reqCache)
        {
            return !(reqCache.IsBadIP);
        }

        /// <summary>
        /// 清除ReqCacheDb中所有的ReqCache对象
        /// </summary>
        internal static void ClearReqCache()
        {
            client.FlushAll();
        }


        /// <summary>
        /// 移除ReqCache
        /// </summary>
        /// <param name="reqID">缓存ReqCache的Key</param>
        internal static bool Remove(string reqID)
        {
            return client.Remove(reqID);
        }
        #endregion

        #region -- Private Herper Method --

        /// <summary>
        /// 获取缓存的过期时间TimeSpan
        /// </summary>
        /// <param name="isForever">是否永远不过期</param>
        /// <returns></returns>
        private static TimeSpan GetCacheTS(bool isForever)
        {
            // if isForever new TimeSpan as 365 days
            return !(isForever) ? new TimeSpan(0, 0, 10, 0) : new TimeSpan(365, 0, 0, 0, 0);
        }
        #endregion
    }
}
